<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <title>DeepSeek 聊天助手</title>
    <script src="/static/js/vue.global.js"></script>
    <script src="/static/js/axios.min.js"></script>
    <link rel="stylesheet" href="/static/css/font-awesome.min.css">
    <link rel="stylesheet" href="/static/css/base.css">
</head>

<body>
    <div id="app" class="app-container">
        <!-- 侧边栏 -->
        <aside class="sidebar">
            <div class="sidebar-user">
                <div class="user-avatar-container" @click="openAvatarUpload">
                    <div class="user-avatar">
                        <i v-if="!currentUser?.avatar" class="fas fa-user"></i>
                        <img v-else :src="currentUser.avatar" class="user-avatar" alt="用户头像">
                    </div>
                    <div class="avatar-upload">
                        <i class="fas fa-camera"></i>
                    </div>
                    <input type="file" accept="image/*" class="hidden" ref="avatarInput" @change="handleAvatarUpload">
                </div>

                <div class="user-info">
                    <div class="user-name">[[ isAuthenticated ? currentUser.username : '未登录' ]]</div>
                    <div class="user-role">
                        [[ isAuthenticated ? (currentUser.is_admin ? '管理员' : '普通用户') : '登录使用完整功能' ]]
                    </div>
                </div>

                <button class="auth-btn login-btn" v-if="!isAuthenticated" @click="openAuthModal">
                    <i class="fas fa-sign-in-alt"></i> 登录/注册
                </button>
                <button class="auth-btn logout-btn" v-if="isAuthenticated" @click="handleLogout">
                    <i class="fas fa-sign-out-alt"></i> 退出登录
                </button>
            </div>

            <div class="sidebar-chat">
                <button class="new-chat-btn" v-if="isAuthenticated" @click="createNewSession">
                    <i class="fas fa-plus"></i> 新话题聊天
                </button>

                <div class="chat-history-header" v-if="isAuthenticated && chatSessions.length > 0">
                    历史聊天话题
                </div>

                <ul class="chat-history-list" v-if="isAuthenticated">
                    <li class="chat-history-item" v-for="(session, index) in displaySessions" :key="session.id"
                        :class="{ active: currentSessionId === session.id }">

                        <!-- 左侧标题 -->
                        <span class="history-title" @click="openSession(session.id)">
                            [[ session.title ]]
                        </span>

                        <!-- 右侧删除图标 -->
                        <i class="fas fa-trash-alt delete-history-btn"
                            @click.stop="deleteCurrentSession(session.id)"></i>
                    </li>

                    <li class="history-more" v-if="chatSessions.length > 3">
                        <span @click="toggleSessionExpand">
                            [[ isSessionExpanded ? '收起' : `查看更多(${chatSessions.length - 3})` ]]
                        </span>
                    </li>
                </ul>

                <div class="chat-history-header" v-else-if="!isAuthenticated">
                    登录后可查看历史聊天
                </div>
            </div>

            <div class="sidebar-config">
                <button class="config-btn" @click="openConfigPage" v-if="isAuthenticated">
                    <i class="fas fa-cog"></i> 系统配置
                </button>
            </div>
        </aside>

        <!-- 主内容区 -->
        <main class="main-content">
            <!-- 首次加载：项目介绍 -->
            <div class="intro-page" v-if="activeView === 'intro' && !isAuthModalOpen">
                <div class="intro-logo">
                    <i class="fas fa-robot"></i>
                </div>
                <h1 class="intro-title">DeepSeek 智能聊天助手</h1>
                <p class="intro-desc">
                    基于 DeepSeek 模型打造的智能交互工具，支持多轮对话、历史记录保存，
                    提供 API Key 管理功能，满足个人与团队的智能协作需求。
                </p>

                <div class="features-container">
                    <div class="feature-card">
                        <div class="feature-icon">
                            <i class="fas fa-comments"></i>
                        </div>
                        <h3 class="feature-title">多轮对话</h3>
                        <p class="feature-desc">支持上下文理解，流畅进行多轮交互</p>
                    </div>
                    <div class="feature-card">
                        <div class="feature-icon">
                            <i class="fas fa-history"></i>
                        </div>
                        <h3 class="feature-title">历史记录</h3>
                        <p class="feature-desc">自动保存聊天历史，随时回溯与续聊</p>
                    </div>
                    <div class="feature-card">
                        <div class="feature-icon">
                            <i class="fas fa-key"></i>
                        </div>
                        <h3 class="feature-title">API 管理</h3>
                        <p class="feature-desc">灵活管理 API Key，控制访问权限</p>
                    </div>
                </div>

                <div class="model-intro">
                    <h3 class="model-intro-title">
                        <i class="fas fa-brain"></i> 模型说明
                    </h3>
                    <p class="feature-desc">
                        当前使用 DeepSeek 系列模型，具备强大的自然语言理解与生成能力，
                        支持代码生成、知识问答、文本创作等场景，响应速度快，准确率高。
                    </p>
                </div>
            </div>

            <!-- 登录/注册弹窗 -->
            <div class="auth-overlay" v-if="isAuthModalOpen">
                <div class="auth-modal">
                    <button class="close-auth" @click="closeAuthModal">
                        <i class="fas fa-times"></i>
                    </button>

                    <div class="tabs">
                        <div class="tab" :class="{ active: isLoginMode }" @click="isLoginMode = true">登录</div>
                        <div class="tab" :class="{ active: !isLoginMode }" @click="isLoginMode = false">注册</div>
                    </div>

                    <div v-if="error" class="error-message">
                        <i class="fas fa-exclamation-triangle"></i> [[ error ]]
                    </div>
                    <div v-if="successMessage" class="success-message">
                        <i class="fas fa-check-circle"></i> [[ successMessage ]]
                    </div>

                    <form @submit.prevent="isLoginMode ? handleLogin() : handleRegister()">
                        <div class="form-group">
                            <label for="username">用户名</label>
                            <input type="text" id="username" v-model="username" required placeholder="请输入用户名">
                        </div>
                        <div class="form-group">
                            <label for="password">密码</label>
                            <input type="password" id="password" v-model="password" required placeholder="请输入密码">
                        </div>
                        <div class="form-group" v-if="!isLoginMode">
                            <label for="email">邮箱（可选）</label>
                            <input type="email" id="email" v-model="email" placeholder="请输入邮箱">
                        </div>
                        <button type="submit" class="auth-button">
                            [[ isLoginMode ? '登录' : '注册' ]]
                        </button>
                    </form>
                </div>
            </div>

            <!-- 聊天页面 -->
            <div class="chat-page" v-if="activeView === 'chat' && currentSessionId">
                <div class="chat-header">
                    <div class="chat-title">
                        <i class="fas fa-comment"></i> 聊天话题：[[ currentSessionTitle ]]
                    </div>
                    <div>
                        <button class="btn-outline" @click="clearCurrentMessages" style="margin-right: 0.5rem;">
                            <i class="fas fa-trash"></i> 清空消息
                        </button>
                        <button class="btn-danger" @click="deleteCurrentSession()">
                            <i class="fas fa-times"></i> 删除话题
                        </button>
                    </div>
                </div>

                <div class="chat-messages">
                    <!-- 历史消息 -->
                    <div v-for="(msg, index) in currentMessages" :key="msg.id"
                        :class="['message', msg.role === 'user' ? 'user-message' : 'assistant-message']">

                        <!-- 头部：用户名 + 时间 + 重发按钮（仅助手且错误时显示） -->
                        <div class="message-meta">
                            <span>[[ msg.role === 'user' ? '你' : 'DeepSeek' ]] · [[ formatDate(msg.created_at) ]]</span>
                            <i v-if="msg.role === 'assistant' && msg.isError" class="fas fa-redo retry-icon"
                                @click="msg.retry" title="重发这条消息"></i>
                        </div>
                        <!-- <div v-if="msg.role==='assistant'">
                            <div v-if="isTyping" class="typing-indicator">
                                <i class="fas fa-circle-notch fa-spin"></i> 正在思考...
                            </div>
                        </div> -->

                        <!-- 内容：富文本（think/code/行内代码 已高亮） -->
                        <div class="message-content">
                            <details v-if="msg.thinkContent" class="think-box">
                                <summary>思考过程（点击展开）</summary>
                                <div class="think-content-wrapper">
                                    <i class="fas fa-circle-notch fa-spin think-spinner"></i>
                                    <pre class="think-content" v-html="msg.thinkContent"></pre>
                                </div>
                            </details>
                            <div v-html="msg.html||msg.content"></div>
                        </div>
                    </div>

                    <!-- 全局错误提示 -->
                    <div v-if="chatError" class="error-message">
                        <i class="fas fa-exclamation-triangle"></i> [[ chatError ]]
                    </div>
                </div>

                <div class="chat-input-container">
                    <input type="file" ref="fileInput" @change="handleSelectFile($event)" style="display:none"
                        accept=".txt,.py,.md,.pdf,.json">
                    <button class="attach-btn" @click="$refs.fileInput.click()" title="上传附件">
                        <i class="fas fa-paperclip"></i>
                    </button>
                    <textarea class="chat-input" v-model="newMessage" placeholder="输入消息..."
                        @keyup.enter.prevent="sendMessage()" :disabled="isTyping"></textarea>
                    <button class="send-btn" @click="sendMessage()" :disabled="isTyping">
                        <i class="fas fa-paper-plane"></i>
                    </button>
                </div>
            </div>

            <!-- 配置页面 -->
            <div class="config-page" v-if="activeView === 'config'">
                <div class="config-header">
                    <h2 class="config-title">系统配置</h2>
                    <div v-if="successMessage" class="success-message" style="margin-top: 0.5rem;">
                        <i class="fas fa-check-circle"></i> [[ successMessage ]]
                    </div>
                </div>

                <div class="config-tabs">
                    <div class="config-tab" :class="{ active: configTab === 'api-key' }" @click="configTab = 'api-key'">
                        API Key 管理
                    </div>
                    <div class="config-tab" :class="{ active: configTab === 'user' }" v-if="currentUser?.is_admin"
                        @click="configTab = 'user'">
                        用户管理
                    </div>
                    <div class="config-tab" :class="{ active: configTab === 'pending-key' }"
                        v-if="currentUser?.is_admin" @click="configTab = 'pending-key'">
                        待激活API Key
                    </div>
                </div>

                <div class="config-content">
                    <!-- API Key 管理 -->
                    <div v-if="configTab === 'api-key'">
                        <div class="section-header"
                            style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem;">
                            <h3>我的 API Key</h3>
                            <button class="btn-success" @click="applyAPIKey()">
                                <i class="fas fa-plus"></i> 申请新 Key
                            </button>
                        </div>

                        <div v-if="apiKeys.length === 0" class="error-message"
                            style="background: #f8fafc; color: #666; border: none;">
                            <i class="fas fa-info-circle"></i> 暂无API Key，请点击上方按钮申请
                        </div>

                        <table class="api-key-table" v-else>
                            <thead>
                                <tr>
                                    <th>序号</th>
                                    <th>API Key</th>
                                    <th>状态</th>
                                    <th>申请时间</th>
                                    <th>操作</th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr v-for="(key, index) in apiKeys" :key="key.id">
                                    <td>[[ index + 1 ]]</td>
                                    <td class="key-display">
                                        [[ key.key ]]
                                    </td>
                                    <td>
                                        <span v-if="!key.is_active && !key.is_revoked" class="badge pending">待审核</span>
                                        <span v-if="key.is_active && !key.is_revoked" class="badge active">已激活</span>
                                        <span v-if="key.is_revoked" class="badge revoked">已注销</span>
                                    </td>
                                    <td>[[ formatDate(key.created_at) ]]</td>
                                    <td>
                                        <button class="key-action-btn btn-danger" v-if="!key.is_revoked"
                                            @click="revokeKey(key.id)">
                                            <i class="fas fa-trash"></i> 注销
                                        </button>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                    </div>

                    <!-- 用户管理（管理员） -->
                    <div v-if="configTab === 'user' && currentUser?.is_admin">
                        <h3 style="margin-bottom: 1.5rem;">用户管理</h3>
                        <table class="user-table">
                            <thead>
                                <tr>
                                    <th>ID</th>
                                    <th>用户名</th>
                                    <th>邮箱</th>
                                    <th>角色</th>
                                    <th>注册时间</th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr v-for="user in allUsers" :key="user.id">
                                    <td>[[ user.id ]]</td>
                                    <td>[[ user.username ]]</td>
                                    <td>[[ user.email || '-' ]]</td>
                                    <td>[[ user.is_admin ? '管理员' : '普通用户' ]]</td>
                                    <td>[[ formatDate(user.created_at) ]]</td>
                                </tr>
                            </tbody>
                        </table>
                    </div>

                    <!-- 待激活API Key（管理员） -->
                    <div v-if="configTab === 'pending-key' && currentUser?.is_admin">
                        <h3 style="margin-bottom: 1.5rem;">待激活API Key</h3>

                        <div v-if="pendingAPIKeys.length === 0" class="error-message"
                            style="background: #f8fafc; color: #666; border: none;">
                            <i class="fas fa-info-circle"></i> 暂无待激活的API Key
                        </div>

                        <table class="api-key-table" v-else>
                            <thead>
                                <tr>
                                    <th>ID</th>
                                    <th>申请人</th>
                                    <th>描述</th>
                                    <th>申请时间</th>
                                    <th>操作</th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr v-for="key in pendingAPIKeys" :key="key.id">
                                    <td>[[ key.id ]]</td>
                                    <td>[[ key.username ]]</td>
                                    <td>[[ key.description ]]</td>
                                    <td>[[ formatDate(key.created_at) ]]</td>
                                    <td>
                                        <button class="key-action-btn btn-success" @click="adminActivateKey(key.id)">
                                            <i class="fas fa-check"></i> 激活
                                        </button>
                                        <button class="key-action-btn btn-danger" @click="adminRevokeKey(key.id)">
                                            <i class="fas fa-times"></i> 拒绝
                                        </button>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </main>
    </div>

    <script>

        /* 复制代码到剪贴板 */
        window.copyCode = function (btn) {
            const block = btn.closest('.code-block');
            const code = block.querySelector('code').innerText;
            navigator.clipboard.writeText(code).then(() => {
                btn.innerHTML = '<i class="fas fa-check"></i> 已复制';
                setTimeout(() => btn.innerHTML = '<i class="fas fa-copy"></i> 复制', 2000);
            });
        };

        const { createApp, reactive, toRefs, onMounted, ref, computed, watch } = Vue;
        const app = createApp({
            setup() {
                const state = reactive({
                    // 基础状态
                    activeView: 'intro', // intro/chat/config
                    isAuthenticated: false,
                    currentUser: null,
                    token: localStorage.getItem('token') || null,

                    // 登录弹窗
                    isAuthModalOpen: false,
                    isLoginMode: true,
                    username: '',
                    password: '',
                    email: '',
                    error: '',
                    successMessage: '',

                    // 聊天相关
                    chatSessions: [],       // 会话列表（历史话题）
                    isSessionExpanded: false,
                    currentSessionId: null, // 当前选中的会话ID
                    currentSessionTitle: '',// 当前会话标题
                    currentMessages: [],    // 当前会话的消息
                    newMessage: '',
                    isTyping: false,
                    chatError: '',

                    // API Key相关
                    apiKeys: [],
                    pendingAPIKeys: [], // 管理员：待激活Key
                    allUsers: [],       // 管理员：所有用户

                    // 配置页面
                    configTab: 'api-key',

                    //附件
                    attachment: "",

                    // API基础路径
                    API_BASE_URL: ''
                });

                // 引用
                const avatarInput = ref(null);

                // 工具函数
                const formatDate = (dateString) => {
                    if (!dateString) return '';
                    return new Date(dateString).toLocaleString();
                };

                const setupAxios = () => {
                    if (state.token) {
                        axios.defaults.headers.common['Authorization'] = `Bearer ${state.token}`;
                    } else {
                        delete axios.defaults.headers.common['Authorization'];
                    }
                };

                // 检查是否有激活的API Key（计算属性）
                const hasActiveAPIKey = computed(() => {
                    return state.apiKeys.some(key => key.is_active && !key.is_revoked);
                });

                // 会话列表显示控制（计算属性）
                const displaySessions = computed(() => {
                    if (state.isSessionExpanded || state.chatSessions.length <= 3) {
                        return state.chatSessions;
                    }
                    return state.chatSessions.slice(0, 3);
                });

                // --------------------------
                // 用户认证相关
                // --------------------------
                const checkAuth = async () => {
                    if (state.token) {
                        setupAxios();
                        try {
                            // 获取当前用户信息
                            const userRes = await axios.get(`{{url_for('auth.get_current_user')}}`);
                            state.currentUser = userRes.data;
                            state.isAuthenticated = true;

                            // 加载会话列表和API Key
                            await loadChatSessions();
                            await loadAPIKeys();

                            // 管理员加载额外数据
                            if (state.currentUser.is_admin) {
                                await loadAdminData();
                            }

                            // 默认选中第一个会话
                            if (state.chatSessions.length > 0) {
                                openSession(state.chatSessions[0].id);
                            }
                        } catch (err) {
                            localStorage.removeItem('token');
                            state.token = null;
                            state.error = '登录状态已失效，请重新登录';
                        }
                    }
                };

                const openAuthModal = () => {
                    state.isAuthModalOpen = true;
                    state.error = '';
                    state.successMessage = '';
                };

                const closeAuthModal = () => {
                    state.isAuthModalOpen = false;
                    state.username = '';
                    state.password = '';
                    state.email = '';
                };

                const handleLogin = async () => {
                    try {
                        state.error = '';
                        const res = await axios.post(
                            "{{ url_for ('auth.login') }}",
                            { username: state.username, password: state.password }
                        );
                        state.token = res.data.access_token;
                        localStorage.setItem('token', state.token);
                        setupAxios();

                        // 获取用户信息
                        const userRes = await axios.get(`{{url_for('auth.get_current_user')}}`);
                        state.currentUser = userRes.data;
                        state.isAuthenticated = true;
                        closeAuthModal();

                        // 加载数据
                        await loadChatSessions();
                        await loadAPIKeys();
                        if (state.currentUser.is_admin) await loadAdminData();

                    } catch (err) {
                        state.error = err.response?.data?.detail || '登录失败，请检查账号密码';
                    }
                };

                const handleRegister = async () => {
                    try {
                        state.error = '';
                        await axios.post(`{{url_for('auth.register')}}`, {
                            username: state.username,
                            password: state.password,
                            email: state.email
                        });
                        state.successMessage = '注册成功，请登录';
                        state.isLoginMode = true;
                    } catch (err) {
                        state.error = err.response?.data?.detail || '注册失败，用户名可能已存在';
                    }
                };

                const handleLogout = () => {
                    state.isAuthenticated = false;
                    state.currentUser = null;
                    state.token = null;
                    state.chatSessions = [];
                    state.currentSessionId = null;
                    state.currentMessages = [];
                    localStorage.removeItem('token');
                    setupAxios();
                    state.activeView = 'intro';
                };

                // 头像上传
                const openAvatarUpload = () => {
                    avatarInput.value?.click();
                };

                const handleAvatarUpload = (e) => {
                    const file = e.target.files[0];
                    if (file) {
                        const reader = new FileReader();
                        reader.onload = async (event) => {
                            const base64 = event.target.result;
                            try {
                                // 上传到后端
                                await axios.post(`{{ url_for('auth.upload_avatar')}}`, {
                                    avatar_base64: base64
                                });
                                // 更新前端头像
                                state.currentUser.avatar = base64;
                                state.successMessage = '头像更新成功';
                                setTimeout(() => state.successMessage = '', 3000);
                            } catch (err) {
                                state.error = '头像上传失败';
                            }
                        };
                        reader.readAsDataURL(file);
                    }
                };

                // --------------------------
                // 聊天会话相关
                // --------------------------
                const loadChatSessions = async () => {
                    try {
                        const res = await axios.get(`{{ url_for("chat.get_chat_sessions")}}`);
                        state.chatSessions = res.data;
                    } catch (err) {
                        state.error = '加载聊天历史失败';
                    }
                };

                const createNewSession = async () => {
                    try {
                        const res = await axios.post(`{{ url_for('chat.create_chat_session') }}`, {
                            title: '新话题'
                        });
                        state.chatSessions.unshift(res.data); // 插入到列表开头
                        openSession(res.data.id); // 选中新会话
                    } catch (err) {
                        state.error = '创建会话失败';
                    }
                };

                const openSession = async (sessionId) => {
                    try {
                        state.currentSessionId = sessionId;
                        state.activeView = 'chat';
                        state.chatError = '';

                        // 获取会话标题
                        const session = state.chatSessions.find(s => s.id === sessionId);
                        if (session) state.currentSessionTitle = session.title;

                        // 获取会话消息
                        const msgRes = await axios.post(
                            "{{ url_for('chat.get_session_messages') }}",
                            `session_id=${sessionId}`,
                        );

                        //  统一包装：用户消息保持原样，助手消息包装成富文本对象
                        state.currentMessages = msgRes.data.map(m =>
                            m.role === 'user'
                                ? { ...m } // 用户消息不需要富文本
                                : {
                                    ...m,
                                    html: formatThinkAndCode(m.content), // 高亮
                                    isError: false,                     // 历史消息默认无错误
                                    retry: null                          // 历史消息不提供重发
                                }
                        );
                    } catch (err) {
                        state.chatError = '加载会话消息失败';
                    }
                };

                const toggleSessionExpand = () => {
                    state.isSessionExpanded = !state.isSessionExpanded;
                };

                const clearCurrentMessages = async () => {
                    if (!state.currentSessionId) return;
                    if (confirm('确定清空当前聊天消息吗？')) {
                        try {
                            await axios.delete(`/api/chat/sessions/${state.currentSessionId}/messages`);
                            state.currentMessages = [];
                            state.successMessage = '消息已清空';
                            setTimeout(() => state.successMessage = '', 2000);
                        } catch (err) {
                            state.chatError = '清空消息失败';
                        }
                    }
                };

                /**
                 * 删除指定话题（不传则删当前会话）
                 * @param {number|null} sessionId  要删的会话 id，空=当前
                 */
                const deleteCurrentSession = async (sessionId = null) => {
                    const targetId = sessionId ?? state.currentSessionId;
                    if (!targetId) return;

                    if (!confirm('确定删除该话题吗？（消息将一并删除）')) return;

                    try {
                        await axios.delete(`/api/chat/sessions/${targetId}`);

                        /* 1. 从列表移除 */
                        state.chatSessions = state.chatSessions.filter(s => s.id !== targetId);

                        /* 2. 如果删的是当前打开的会话，需要切换 */
                        if (state.currentSessionId === targetId) {
                            if (state.chatSessions.length > 0) {
                                openSession(state.chatSessions[0].id);   // 切到第一个
                            } else {
                                // 没有会话可切，回 intro
                                state.currentSessionId = null;
                                state.currentMessages = [];
                                state.activeView = 'intro';
                            }
                        }

                        state.successMessage = '话题已删除';
                        setTimeout(() => state.successMessage = '', 2000);
                    } catch (err) {
                        state.error = err.response?.data?.error || '删除失败';
                    }
                };

                // --------------------------
                // 聊天消息相关
                // --------------------------
                const handleSelectFile = async (e) => {
                    console.log('start upload file...');
                    const file = e.target.files[0];
                    if (!file) return;
                    const form = new FormData();
                    form.append("file", file);
                    try {
                        const res = await axios.post("/api/chat/upload", form, {
                            headers: { "Content-Type": "multipart/form-data" }
                        });
                        this.attachment = res.data.text;
                        this.successMessage = `已加载附件：${file.name}`;
                    } catch (err) {
                        this.error = err.response?.data?.error || "附件上传失败";
                    }
                }
                const sendMessage = async () => {
                    if (!state.newMessage.trim() || !state.currentSessionId) return;

                    const userContent = state.attachment
                        ? `用户问题：${state.newMessage}\n\n附件内容：\n${state.attachment}`
                        : state.newMessage;

                    /* 1. 用户消息立即可见 */
                    state.currentMessages.push({
                        id: Date.now(),
                        role: 'user',
                        content: userContent,
                        created_at: new Date().toISOString()
                    });

                    const assistantMsg = {
                        id: Date.now() + 1,
                        role: 'assistant',
                        content: '',      // 纯文本累加
                        html: '',         // Markdown 富 HTML（实时更新）
                        thinkContent: '',    // Think 折叠 HTML（实时更新）
                        isError: false,
                        created_at: new Date().toISOString(),
                        retry: null
                    };
                    state.currentMessages.push(assistantMsg);
                    state.isTyping = true;
                    state.newMessage = '';
                    state.attachment = '';


                    try {
                        let is_thinkMsg = false;
                        state.isTyping = true;

                        // 1. 发送请求（支持自定义 headers）
                        const response = await fetch(`{{ url_for('chat.stream_chat') }}`, {
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/json',
                                'Authorization': `Bearer ${localStorage.getItem('token')}`
                            },
                            body: JSON.stringify({
                                session_id: state.currentSessionId,
                                message: userContent,
                                attachment: ''
                            })
                        });
                        if (!response.ok) throw new Error(`请求失败: ${response.status}`);

                        // 2. 处理流式响应
                        const reader = response.body.getReader();
                        const decoder = new TextDecoder();

                        // 循环读取流数据
                        while (true) {
                            const { done, value } = await reader.read();
                            if (done) break;

                            // 3. 实时解码并更新输出（打字机效果）
                            const chunk = decoder.decode(value, { stream: true });
                            let { content } = JSON.parse(chunk);

                            if (content && content.startsWith('<think>')) {
                                is_thinkMsg = true;
                                continue;
                            }
                            if (content && content.startsWith('</think>')) {
                                is_thinkMsg = false;
                                continue;
                            }
                            // 逐字追加（控制速度模拟打字效果）
                            for (const char of data.content) {
                                // state.outputText += char;
                                if (is_thinkMsg)
                                    assistantMsg.thinkContent += char;
                                else
                                    assistantMsg.html += char;

                                await new Promise(resolve => setTimeout(resolve, 10)); // 打字速度
                            }
                        }

                    } catch (err) {
                        assistantMsg.html += `错误: ${err.message}`;
                    } finally {
                        state.isLoading = false;
                        state.isTyping = false;
                    }

                    // 等待补充
                };
                // --------------------------
                // API Key相关
                // --------------------------
                const loadAPIKeys = async () => {
                    try {
                        const res = await axios.get(`{{ url_for('auth.get_user_keys') }}`);
                        state.apiKeys = res.data;
                    } catch (err) {
                        state.error = '加载API Key失败';
                    }
                };

                const applyAPIKey = async () => {
                    try {
                        const res = await axios.post(`{{ url_for('auth.create_user_key') }}`, {
                            description: '默认API Key'
                        });
                        state.apiKeys.unshift(res.data);
                        state.successMessage = 'API Key申请已提交，等待管理员激活';
                        setTimeout(() => state.successMessage = '', 3000);
                    } catch (err) {
                        state.error = '申请API Key失败';
                    }
                };

                const revokeKey = async (keyId) => {
                    if (confirm('确定注销此API Key吗？')) {
                        try {
                            await axios.post("{{ url_for('auth.revoke_user_key') }}", `key_id=${keyId}`);
                            // 更新前端状态
                            const key = state.apiKeys.find(k => k.id === keyId);
                            if (key) {
                                key.is_revoked = true;
                                key.is_active = false;
                            }
                            state.successMessage = 'API Key已注销';
                            setTimeout(() => state.successMessage = '', 2000);
                        } catch (err) {
                            state.error = '注销API Key失败';
                        }
                    }
                };

                // --------------------------
                // 管理员相关
                // --------------------------
                const loadAdminData = async () => {
                    try {
                        // 获取所有用户
                        const usersRes = await axios.get(`{{ url_for('admin.get_users') }}`);
                        state.allUsers = usersRes.data;

                        // 获取待激活API Key
                        const keysRes = await axios.get(`{{ url_for('admin.get_pending_api_keys') }}`);
                        state.pendingAPIKeys = keysRes.data;
                    } catch (err) {
                        state.error = '加载管理员数据失败';
                    }
                };

                const adminActivateKey = async (keyId) => {
                    try {
                        await axios.post('{{ url_for("admin.activate_api_key") }}', `key_id=${keyId}`);
                        // 更新待激活列表
                        state.pendingAPIKeys = state.pendingAPIKeys.filter(k => k.id !== keyId);
                        // 刷新用户API Key列表（如果当前在API Key页面）
                        if (state.configTab === 'api-key') await loadAPIKeys();
                        state.successMessage = 'API Key已激活';
                        setTimeout(() => state.successMessage = '', 2000);
                    } catch (err) {
                        state.error = '激活API Key失败';
                    }
                };

                const adminRevokeKey = async (keyId) => {
                    try {
                        await axios.post('{{ url_for("admin.revoke_api_key") }}', `key_id=${keyId}`);
                        state.pendingAPIKeys = state.pendingAPIKeys.filter(k => k.id !== keyId);
                        state.successMessage = 'API Key已拒绝';
                        setTimeout(() => state.successMessage = '', 2000);
                    } catch (err) {
                        state.error = '操作失败';
                    }
                };

                // --------------------------
                // 配置页面相关
                // --------------------------
                const openConfigPage = () => {
                    state.activeView = 'config';
                    state.configTab = 'api-key';
                    state.successMessage = '';
                    state.error = '';
                    // 刷新数据
                    loadAPIKeys();
                    if (state.currentUser?.is_admin) loadAdminData();
                };

                // --------------------------
                // 初始化
                // --------------------------
                onMounted(() => {
                    setupAxios();
                    checkAuth();

                    // 监听会话ID变化，自动滚动到底部
                    watch(() => state.currentMessages, () => {
                        setTimeout(() => {
                            const chatContainer = document.querySelector('.chat-messages');
                            if (chatContainer) chatContainer.scrollTop = chatContainer.scrollHeight;
                        }, 100);
                    }, { deep: true });
                });

                return {
                    ...toRefs(state),
                    avatarInput,
                    hasActiveAPIKey,
                    displaySessions,
                    formatDate,
                    setupAxios,
                    // 用户认证
                    checkAuth,
                    openAuthModal,
                    closeAuthModal,
                    handleLogin,
                    handleRegister,
                    handleLogout,
                    openAvatarUpload,
                    handleAvatarUpload,
                    // 聊天会话
                    loadChatSessions,
                    createNewSession,
                    openSession,
                    toggleSessionExpand,
                    clearCurrentMessages,
                    deleteCurrentSession,
                    // 聊天消息
                    sendMessage,
                    handleSelectFile,

                    // API Key
                    loadAPIKeys,
                    applyAPIKey,
                    revokeKey,
                    // 管理员
                    loadAdminData,
                    adminActivateKey,
                    adminRevokeKey,
                    // 配置页面
                    openConfigPage,
                };
            }
        });

        // Vue3 分隔符配置
        app.config.compilerOptions.delimiters = ['[[', ']]'];
        app.mount('#app');
    </script>
</body>

</html>